package com.learn.smart.framework.util;

import java.io.File;
import java.io.FileFilter;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ClassUtil {
	
	private static final Logger log = LoggerFactory.getLogger(ClassUtil.class);

	/**获取类加载器*/
	public static ClassLoader getClassLoader(){
		return Thread.currentThread().getContextClassLoader();
	}
	
	public static Set<Class<?>> getClassSet(String packageName){
		Set<Class<?>> classSet = new HashSet<Class<?>>();
		try {
			Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".", "/"));
			while(urls.hasMoreElements()){
				URL url = urls.nextElement();
				if(url!=null){
					String protocol = url.getProtocol();
					if(protocol.equals("file")){//自己写文件
						String packagePath = url.getPath().replace("%20", " ");
						if(packagePath.startsWith("/")){
							packagePath=packagePath.substring(1);
						}
						addClass(classSet,packagePath,packageName);
					}else if(protocol.equals("jar")){//引用的jar包
						JarURLConnection jarURLConnection = (JarURLConnection)url.openConnection();
						if(jarURLConnection!=null){
							JarFile jarFile = jarURLConnection.getJarFile();
							if(jarFile!=null){
								Enumeration<JarEntry> jarEntries =  jarFile.entries();
								while(jarEntries.hasMoreElements()){
									JarEntry jarEntry = jarEntries.nextElement();
									String jarEntryName = jarEntry.getName();
									if(jarEntryName.equals(".class")){
										String className =  jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", ".");
										doAddClass(classSet,className);
									}
								}
							}
						}
					}
				}
			}
		} catch (Exception e) {
			log.error("加载类集合失败",e);
			e.printStackTrace();
		}
		return classSet;
	}
	
	private static void addClass(Set<Class<?>> classSet,String packagePath,String packageName) throws Exception{
		File[] files = new File(packagePath).listFiles(new FileFilter(){
			@Override
			public boolean accept(File file) {
				return (file.isFile()&&file.getName().endsWith(".class"))||file.isDirectory();
			}
		});
		for(File file : files){
			if(file.isFile()){
				String fileName = file.getName();
				String className = fileName.substring(0, fileName.lastIndexOf("."));
				if(StringUtils.isNotEmpty(packageName)){
					className=packageName+"."+className;
				}
				doAddClass(classSet,className);
			}else{
				String fileName = file.getPath();
				//迭代
				String subPackagePath = fileName;
//				if(StringUtils.isNotEmpty(packagePath)){
//					subPackagePath = packagePath+"/"+subPackagePath;
//				}
				String subPackageName = fileName.substring(fileName.lastIndexOf("\\")+1);
				if(StringUtils.isNotEmpty(packageName)){
					subPackageName = packageName+"."+subPackageName;
				}
				addClass(classSet,subPackagePath,subPackageName);
			}
		}
	}
	
	private static void doAddClass(Set<Class<?>> classSet,String className) throws Exception{
		Class<?> cls = loadClass(className,false);
		classSet.add(cls);
	}
	
	public static void loadClass(String className){
		try {
			loadClass(className,false);
		} catch (ClassNotFoundException e) {
			log.error("加载类失败",e);
			e.printStackTrace();
		}
	}
	
	public static Class<?> loadClass(String className,boolean isInitialized) throws ClassNotFoundException{
		Class<?> cls;
		try {
			cls = Class.forName(className, isInitialized, getClassLoader());
		} catch (ClassNotFoundException e) {
			log.error("加载类失败",e);
			throw e;
		}
		return cls;
	}
	
	
}
